using System;
using System.Collections.Generic;
using System.ComponentModel.Design;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;



namespace EuphoricEngine3D
{
    public class Engine
    {
        private Game _game = null;
        private GameTime _gameTime = null;

        private PythonInterpreter _interp;

        private IEContentManager _content = null;
        private GraphicsDevice _graphicsDevice = null;
        private SpriteBatch _spriteBatch = null;
        private IEServiceContainer _services = null;

        private bool _paused;
        private bool _oldPaused;

        private List<GameScreen> _gameScreens = new List<GameScreen>();

        public Engine(Game game, string consoleFont, GraphicsDeviceManager graphics)
        {
            _game = game;

            _services = new IEServiceContainer();
            _services.AddService(typeof(IGraphicsDeviceService), graphics);
            _services.AddService(typeof(IGraphicsDeviceManager), graphics);

            _graphicsDevice = graphics.GraphicsDevice;
            _content = new IEContentManager(Services, "Content");
            _spriteBatch = new SpriteBatch(GraphicsDevice);
            _graphicsDevice = GraphicsDevice;

            TextHandler.Initialize(_spriteBatch, _content, "Fonts");

            _interp = new PythonInterpreter(game, TextHandler.GetFont(consoleFont));
            _game.Components.Add(_interp);

            _interp.AddGlobal("this", this);
            _interp.Console.OnClosed += new EventHandler(Console_OnClosed);
            _interp.Console.OnOpening += new EventHandler(Console_OnOpening);
        }

        public Engine(Game game, string consoleFont, GraphicsDeviceManager graphics, string contentRootFolder)
        {
            _game = game;

            _services = new IEServiceContainer();
            _services.AddService(typeof(IGraphicsDeviceService), graphics);
            _services.AddService(typeof(IGraphicsDeviceManager), graphics);

            _graphicsDevice = graphics.GraphicsDevice;
            _content = new IEContentManager(Services, contentRootFolder);
            _spriteBatch = new SpriteBatch(GraphicsDevice);
            _graphicsDevice = GraphicsDevice;

            TextHandler.Initialize(_spriteBatch, _content, "Fonts");

            _interp = new PythonInterpreter(game, TextHandler.GetFont(consoleFont));
            _game.Components.Add(_interp);

            _interp.AddGlobal("this", this);
            _interp.Console.OnClosed += new EventHandler(Console_OnClosed);
            _interp.Console.OnOpening += new EventHandler(Console_OnOpening);
        }

        public void PushGameScreen(GameScreen gameScreen)
        {
            if (gameScreen.Engine != null)
                throw new Exception("This GameScreen already exists on the stack of another Engine instance!");

            if (!_gameScreens.Contains(gameScreen))
            {
                _gameScreens.Add(gameScreen);
                gameScreen.Engine = this;
                gameScreen.LoadGameScreen();
            }
        }

        public GameScreen PopGameScreen()
        {
            if (_gameScreens.Count == 0)
                return null;

            GameScreen gameScreen =  _gameScreens[_gameScreens.Count - 1];

            gameScreen.Engine = null;
            _gameScreens.Remove(gameScreen);

            return gameScreen;
        }

        void Console_OnClosed(object sender, EventArgs e)
        {
            _paused = _oldPaused;
        }

        void Console_OnOpening(object sender, EventArgs e)
        {
            _oldPaused = _paused;
            _paused = true;
        }

        public void Update(GameTime gameTime)
        {
            _gameTime = gameTime;

            if (!_paused)
            {
                _game.Window.Title = _gameTime.TotalRealTime.ToString();

                List<GameScreen> updating = new List<GameScreen>();

                foreach (GameScreen gameScreen in _gameScreens)
                    updating.Add(gameScreen);

                foreach (GameScreen gameScreen in updating)
                    gameScreen.Update();
            }
        }

        public void Draw(GameTime gameTime)
        {
            _gameTime = gameTime;

            foreach (GameScreen gameScreen in _gameScreens)
                gameScreen.Draw();

            _spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

            // Specify our defaults
            TextHandler.CurrentFont = "Pericles10";
            TextHandler.CurrentColor = Color.White;

            // Draw some text in each of our fonts
            TextHandler.DrawText("Test Pericles8", 10, 10, "Pericles8");
            TextHandler.DrawText("Pericles10", 10, 30, "Pericles10");
            TextHandler.DrawText("Pericles12", 10, 50, "Pericles12");
            TextHandler.DrawText("Pericles14", 10, 70, "Pericles14");
            TextHandler.DrawText("Lindsey20", 10, 110, "Lindsey20");

            // Demonstrate the "console" text handling
            TextHandler.CursorLocation = new Vector2(300, 10);
            TextHandler.Print("Hello, world!");
            TextHandler.Print("This text demonstrates automatic");
            TextHandler.Print("Text console handling!");

            // Draw some word-wrapped text in yellow

            TextHandler.CurrentColor = Color.Yellow;
            TextHandler.Print(TextHandler.WrapText("This Line of Text is Wrapped " +
            "to be no more than 75 pixels wide!", 75));
            TextHandler.Print("And this one isn't!");

            // Draw some parsed text, wordwrapping it to 250 pixels wide.
            TextHandler.CurrentColor = Color.White;
            TextHandler.DrawTextParsed("This is ![#FFFF00]Yellow ![#FFFFFF] and " +
            "![#0000FF]Blue ![#FFFFFF] " +
            "and ![#FF0000]![F:Pericles14Bold] RED! " +
            "![F:Pericles14]![#FFFFFF]text " +
            "![F:Pericles14Bold]![#0000FF]Blue Bold " +
            "![F:Pericles14]![#FFFFFF]with " +
            "[brackets!] and lots of text and the " +
            "end to make sure wrapping is working ok.",
            10, 250, "Pericles14", 250);

            _spriteBatch.End();
        }

        public void PauseGame()
        {
            _paused = true;
        }
        public void ResumeGame()
        {
            _paused = false;
        }

        public void Shutdown()
        {
            _game.Exit();
        }

        public Game Game { get { return _game; } }
        public bool Paused { get { return _paused; } }
        public GameTime GameTime { get { return _gameTime; } }
        public PythonInterpreter Interp { get { return _interp; } }
        public Console Console { get { return _interp.Console; } }
        public IEContentManager Content { get { return _content; } }
        public GraphicsDevice GraphicsDevice { get { return _graphicsDevice; } }
        public SpriteBatch SpriteBatch { get { return _spriteBatch; } }
        public IEServiceContainer Services { get { return _services; } }
        public List<GameScreen> GameScreens { get { return _gameScreens; } }
    }
}
